-- interrupt package for skeleton test program skel2 for trains --
-- requires Swindows, Simrail2 (vsn 2.0.4 +), Raildefs
-- and Halls2 & Io_Ports for Simrail2
--
-- Version: 1.0 extracted from skel2 for GNAT2009, 19-Feb-09
-- Version: 1.1 hide protected, 16-Mar-10
--
-- Copyright: Dr R. K Allen, faculty of ICT, Swinburne UT
--
with Ada.Integer_Text_Io;
with Swindows;  use Swindows;
with Unsigned_Types;  use Unsigned_Types;  -- 1.8
with
      Raildefs,
      Int32defs,
      Halls2;
use Raildefs;

package body Interrupt_Hdlr is

   W_Interrupts : Swindows.Window;

   package Iio renames Ada.Integer_Text_Io;

   subtype String8 is String(1..8);  -- cant be declared in a protected.

   protected Interrupt is
      procedure Analyze(
         Offset : in Raildefs.Sensor_Idx;  -- 0 or 32
         Value  : in Raildefs.Four_Registers); -- vsn 2.0.5
            -- this procedure conforms to Raildefs.Proc4_Access
   private
      Number : Natural := 1;
      Line_Number : Natural := 1;
      Fg : Swindows.Color := Swindows.White;
      S : String(1..78) := (1..4|13|22|31|40|49|58|67|76..78 => ' ', others => '.');
      function To_String(Val : Unsigned_8) return String8;
   end Interrupt;

   procedure Init(Win : in Swindows.Window) is
   begin
      W_Interrupts := Win;
   end Init;

   procedure Install is  -- added v1.1
   begin
      Halls2.Install_Int_Handling(Interrupt.Analyze'access);
   end Install;


   protected body Interrupt is

      -- this version just displays all the current states:
      -- it takes too much screen space
      procedure Analyze(
         Offset : in Raildefs.Sensor_Idx;
         Value  : in Raildefs.Four_Registers) is
      --
         use Int32defs;
      begin
         Iio.Put(S(1..3), Number);
         -- display sensor bytes and turnout nibble in binary ('.'=1)
         if Offset = 0 then -- sensors 1..32
            S( 5..12) := To_String(Value(0));
            S(14..21) := To_String(Value(1));
            S(23..30) := To_String(Value(2));
            S(32..39) := To_String(Value(3));
         else  -- sensors 33..64
            S(41..48) := To_String(Value(0));
            S(50..57) := To_String(Value(1));
            S(59..66) := To_String(Value(2));
            S(68..75) := To_String(Value(3));
         end if;
         -- last byte is time in 100ths of sec for testing simrail:
         if Value'last = 4 then  -- (a bit of future-proofing)
            Iio.Put(S(76..78), Integer(Value(4)));  -- added v.1.5.2
         end if;
        -- Put_Line(W_Interrupts, S, Line_Number, Foreground=>Fg);
         Number := (Number + 1) mod 1000;  -- serial number
         Line_Number := (Line_Number mod 14) + 1;
         if Line_Number = 1 then
            if Fg = White then Fg := Yellow; else Fg := White; end if;
         end if;

      exception
         when Constraint_Error =>
         --   Put_Line(W_Interrupts, "int constraint", (Number mod 14) + 1);
		 null;
         when Tasking_Error =>
		 null;
            --Put_Line(W_Interrupts, "int tasking", (Number mod 14) + 1);
         when others =>
            --Put_Line(W_Interrupts, "int others", (Number mod 14) + 1);
			null;
      end Analyze;

      function To_String(Val : Unsigned_8) return String8 is
         use Int32defs;
         V : Sensor_Register := Unsigned_8_To_Sensor_Register(Val);
         Result : String8 := "........";
      begin
         for I in Sensor_Idx range 0..7 loop  -- note display LSB on left
            if V(I) = Raildefs.On then Result(Integer(I)+1) := '0'; end if;
         end loop;
         return Result;
      end To_String;

   end Interrupt;

end Interrupt_Hdlr;
